package edu.hit.pact.pgse.crawler.bbs;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.commons.logging.Log;

import edu.hit.pact.pgse.crawler.download.WebPageFetcher;
import edu.hit.pact.pgse.crawler.store.WebPageStore;
import edu.hit.pact.pgse.crawler.util.Anchor;
import edu.hit.pact.pgse.crawler.util.CustomHttpClient;
import edu.hit.pact.pgse.util.Globals;

public abstract class AbstractBBSFetchorThread extends Thread{

	protected Log logger;
	protected WebPageFetcher fetcher= null;
	protected WebPageStore webPageStore;
	//protected ConcurrentLinkedQueue<URL> articleUrlQueue;
	protected ConcurrentLinkedQueue<Anchor> articleAnchorQueue;
	protected int successedPageNum = 0;
	protected URL homepage = null;
	protected static AtomicInteger aliveThreadCnt ;
	protected AtomicBoolean isFinished;
	
	/*static*/protected Calendar beginCalendar = Calendar.getInstance();
	/*static*/protected Calendar endCalendar = Calendar.getInstance(); //the reason of not use static is the variable is shared
	
	
	public AbstractBBSFetchorThread(Log logger, WebPageFetcher fetcher,
			WebPageStore webPageStore,ConcurrentLinkedQueue<URL> articleUrlQueue,
			String threadName) {
		
		super(threadName);
		this.logger = logger;
		this.fetcher = fetcher;
		this.webPageStore = webPageStore;
		//this.articleUrlQueue = articleUrlQueue;
		this.isFinished.set(false);
		aliveThreadCnt = new AtomicInteger(0);		
		setCalendar();
	}
	public AbstractBBSFetchorThread(Log logger, WebPageFetcher fetcher,
			WebPageStore webPageStore,ConcurrentLinkedQueue<Anchor> articleAnchorQueue,
			String threadName,AtomicBoolean isFinished) {
		
		super(threadName);
		this.logger = logger;
		this.fetcher = fetcher;
		this.webPageStore = webPageStore;
		this.articleAnchorQueue = articleAnchorQueue;
		this.isFinished = isFinished;
		aliveThreadCnt = new AtomicInteger(0);		
		this.isFinished = isFinished;
		setCalendar();
	}
	
	
	public AbstractBBSFetchorThread(String threadName,Log logger){
		super(threadName);
		this.logger = logger;
	}
	
	public int getSuccessedPageNum() {
		return successedPageNum;
	}
	
	public void setSuccessedPageNum(int successedPageNum) {
		this.successedPageNum = successedPageNum;
	}

	public URL getHomepage() {
		return homepage;
	}

	public void setHomepage(URL homepage) {
		this.homepage = homepage;
	}

	
	
	
	@Override
	public void run() {
		logger.info(this.getName() + " is running.");
	    aliveThreadCnt.incrementAndGet();
		try {
			mainRun();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	    aliveThreadCnt.decrementAndGet();
		logger.info(this.getName() + " completed " + successedPageNum
				+ " pages.");
	}
	
	
	public WebPageFetcher buildWebPageFetcher(){
		/*
		 * Construct HttpClient and WegPageFetcher
		 */
		//logger.info("construct httpclient.");
		
		logger.info(this.getName() + " rebuild fetcher.");
		int maxPerHostConnection = Globals.CRAWLER_DEFAULT_MAX_PERHOST_CONNECTIONS;
		int maxTotalConnection = Globals.CRAWLER_DEFAULT_MAX_TOTAL_CONNECTIONS;
		int connectTimeout = Globals.CRAWLER_CONNECT_TIMEOUT;
		CustomHttpClient httpClient = new CustomHttpClient(maxPerHostConnection, maxTotalConnection, connectTimeout);
		
		if (Globals.CRAWLER_USE_PROXY) {
			String proxyIp = Globals.CRAWLER_PROXY_IP;
			int proxyPort = Globals.CRAWLER_PROXY_PORT;
			
			//logger.info("set proxy : ip :" + proxyIp + " port :" + proxyPort);			
			httpClient.setProxy(proxyIp, proxyPort);
		}//end if
		
		//logger.info("construct web page fetcher.");
		String defalutCharSet = Globals.CRAWLER_WEB_DEFAULT_CHARSET;
		int readTimeout = Globals.CRAWLER_READ_TIMEOUT;
		int maxContentLength = Globals.CRAWLER_MAX_CONTENT_LENGTH;
		
		WebPageFetcher webPageFetcher = new WebPageFetcher(httpClient, defalutCharSet, readTimeout, maxContentLength);
		return webPageFetcher;
	}
	
	abstract public void mainRun() throws MalformedURLException,InterruptedException;
	 
	protected boolean shedule(boolean isShedule){
		
		if(!isShedule){
			return false;
		}
		Calendar calendar = Calendar.getInstance();
		int hour = calendar.get(Calendar.HOUR_OF_DAY);
		if(hour >=0 && hour <= 7){
			return false;
		}
		
		Date now = new Date();
		Date desDate = this.beginCalendar.getTime();
		long interval = desDate.getTime() - now.getTime();
		while(interval < 0){
			this.beginCalendar.add(Calendar.DAY_OF_MONTH, 1);
			desDate = this.beginCalendar.getTime();
			interval = desDate.getTime() - now.getTime();
		}
		
		try {
			logger.error(this.getName()+" will sleep " + interval/1000 + "s.");
			sleep(interval);
			return true;
		} catch (InterruptedException e) {
			e.printStackTrace();
			return false;
		}
		
	}

	private void  setCalendar(){
		this.beginCalendar.set(Calendar.HOUR_OF_DAY, 0);
		this.beginCalendar.set(Calendar.MINUTE, 0);
		this.beginCalendar.set(Calendar.SECOND, 0);
		
		this.endCalendar.set(Calendar.HOUR_OF_DAY, 10);
		this.endCalendar.set(Calendar.MINUTE, 0);
		this.endCalendar.set(Calendar.MINUTE, 0);
		
	}
	
}
